﻿using OneDrive;
using System;
using System.Collections.Generic;
using System.IO;
using ZquenceStudio3Host.Storage.FileSystemStorage.BuiltInPlugins;

namespace Zquence_Studio_3.Shared
{
    internal class OnedriveHelper
    {
        private ODItem _sourceItem;
        private ODConnection _connection;
        private bool _selected;
        private string clientId;
        private string clientSecret;

        public OnedriveHelper(string clientId, string clientSecret)
        {
            this.clientId = clientId;
            this.clientSecret = clientSecret;
        }

        public ODConnection Connection
        {
            get { return _connection; }
            set
            {
                if (value == _connection)
                    return;
                _connection = value;
                //SourceItemChanged(); 
            }
        }

        public bool IsAuthorizated
        {
            get
            {
                return Connection != null;
            }
        }

        public string ClientId { get { return clientId; } }

        public string ClientSecret { get { return clientSecret; } }

        private string FixPath(string path)
        {
            if (path.Length > 0)
            {
                path = path.Replace("\\", "/");
                if (!path.EndsWith("/"))
                {
                    path += "/";
                }

                if (path.StartsWith("./"))
                {
                    path = path.Substring(2);
                }

                path = path.Replace("/", ":/");
            }

            //reference.Path = "/drive/root:/Appar/Zquence%20Studio/Albums";
            //reference.Path = "/drive/special/approot/:Zquence%20Studio/Albums";
            //reference.Path = "/drive/special/approot:/Albums:/"; <-- Working.
            return "/drive/special/approot:/" + path;
        }

        private string FixPathForCreateFile(string path)
        {
            if (path.Length > 0)
            {
                path = path.Replace("\\", "/");
                if (!path.EndsWith("/"))
                {
                    path += "/";
                }

                if (path.StartsWith("./"))
                {
                    path = path.Substring(2);
                }

                path = path.Replace("/", ":/");
            }

            //reference.Path = "/drive/root:/Appar/Zquence%20Studio/Albums";
            //reference.Path = "/drive/special/approot/:Zquence%20Studio/Albums";
            //reference.Path = "/drive/special/approot:/Albums:/"; <-- Working.
            return "/drive/special/approot/" + path;
        }

        private string FixPathForCreateFileOnSubFolders(string path)
        {
            if (path.Length > 0)
            {
                path = path.Replace("\\", "/");
                if (!path.EndsWith("/"))
                {
                    path += "/";
                }

                if (path.StartsWith("./"))
                {
                    path = path.Substring(2);
                }

                path = path.Replace("/", ":/");
            }

            //reference.Path = "/drive/root:/Appar/Zquence%20Studio/Albums";
            //reference.Path = "/drive/special/approot/:Zquence%20Studio/Albums";
            //reference.Path = "/drive/special/approot:/Albums:/"; <-- Working.
            return "/drive/special/approot:/" + path;
        }
        
        private string FixPathForOpen(string path)
        {
            if (path.Length > 0)
            {
                path = path.Replace("\\", "/");

                if (path.StartsWith("./"))
                {
                    path = path.Substring(2);
                }

                path = path.Replace("/", ":/");
            }

            //reference.Path = "/drive/root:/Appar/Zquence%20Studio/Albums";
            //reference.Path = "/drive/special/approot/:Zquence%20Studio/Albums";
            //reference.Path = "/drive/special/approot:/Albums:/"; <-- Working.
            return "/drive/special/approot:/" + path;
        }

        private string FixPathForOpenSubFolders(string path)
        {
            if (path.Length > 0)
            {
                path = path.Replace("\\", "/");

                if (path.StartsWith("./"))
                {
                    path = path.Substring(2);
                }

                //path = path.Replace("/", ":/");
            }

            //reference.Path = "/drive/root:/Appar/Zquence%20Studio/Albums";
            //reference.Path = "/drive/special/approot/:Zquence%20Studio/Albums";
            //reference.Path = "/drive/special/approot:/Albums:/"; <-- Working.
            return "/drive/special/approot:/" + path;
        }

        public async void ListFiles(string onedrivePath, EventHandler<ListFilesResult> callback)
        {
            onedrivePath = FixPath(onedrivePath);

            var reference = ODConnection.ItemReferenceForSpecialFolder("approot", onedrivePath);
            reference.Path = onedrivePath;
            var res2 = await Connection.GetChildrenOfItemAsync(reference, ChildrenRetrievalOptions.Default);

            ListFilesResult callbackResult = new ListFilesResult();
            List<string> files = new List<string>();
            foreach (var item in res2.Collection)
            {
                // Check if file.
                if (item.File != null)
                {
                    files.Add(item.Name);
                }
            }
            callbackResult.Files = files.ToArray();

            callback(this, callbackResult);
        }

        public async void ListFolders(string onedrivePath, EventHandler<ListFoldersResult> callback)
        {
            onedrivePath = FixPath(onedrivePath);

            var reference = ODConnection.ItemReferenceForSpecialFolder("approot", onedrivePath);

            reference.Path = onedrivePath;

            var res2 = await Connection.GetChildrenOfItemAsync(reference, ChildrenRetrievalOptions.Default);

            ListFoldersResult callbackResult = new ListFoldersResult();
            List<string> folders = new List<string>();
            foreach (var item in res2.Collection)
            {
                // Check if file.
                if (item.Folder != null)
                {
                    folders.Add(item.Name + "/");
                }
            }
            callbackResult.Folders = folders.ToArray();

            callback(this, callbackResult);
        }

        /// <summary>
        /// Reference: https://dev.onedrive.com/items/download.htm
        /// </summary>
        /// <param name="onedrivePath"></param>
        /// <param name="callback"></param>
        public async void OpenFile(string onedrivePath, EventHandler<OpenFileResult> callback)
        {
            try
            {
                var splitted = onedrivePath.Split('/');
                if (splitted.Length > 2)
                {
                    // Subfolders.
                    onedrivePath = FixPathForOpenSubFolders(onedrivePath);
                }
                else
                {
                    onedrivePath = FixPathForOpen(onedrivePath);
                }

                var reference = ODConnection.ItemReferenceForSpecialFolder("approot", onedrivePath);

                reference.Path = onedrivePath;

                var res2 = await Connection.GetItemAsync(reference, ItemRetrievalOptions.Default);

                var stream = await res2.GetContentStreamAsync(Connection, StreamDownloadOptions.Default);

                OpenFileResult callbackResult = new OpenFileResult();
                callbackResult.FileStream = stream;
                callback(this, callbackResult);
            }
            catch (Exception error)
            {
                OpenFileResult callbackResult = new OpenFileResult();
                callbackResult.Error = error;
                callbackResult.Success = false;
                callback(this, callbackResult);
            }
        }

        public async void Exist(string onedrivePath, bool isDirectory, EventHandler<ExistResult> callback)
        {
            // TODO: Tryck in koden under innuti FixPathForOpen istället.
            // Gör en ordentlig rensning i OndedriveControl..........
            var splitted = onedrivePath.Split('/');
            if (splitted.Length > 2)
            {
                // Subfolders.
                onedrivePath = FixPathForOpenSubFolders(onedrivePath);
            }
            else
            {
                onedrivePath = FixPathForOpen(onedrivePath);
            }

            var reference = ODConnection.ItemReferenceForSpecialFolder("approot", onedrivePath);

            reference.Path = onedrivePath;

            ExistResult callbackResult = new ExistResult();
            try
            {
                var res2 = await Connection.GetItemAsync(reference, ItemRetrievalOptions.Default);
                if (isDirectory)
                {
                    callbackResult.Exist = res2.Folder != null;
                }
                else
                {
                    callbackResult.Exist = res2.File != null;
                }
            }
            catch (Exception error)
            {
                callbackResult.Exist = false;
            }

            callback(this, callbackResult);
        }

        public async void UploadFile(Stream localFile, string onedrivePath, EventHandler<UploadFileResult> callback)
        {
            string fixedOnedrivePath = onedrivePath.Replace("\\", "/");
            string filename = fixedOnedrivePath.Substring(fixedOnedrivePath.LastIndexOf("/") + 1);
            string folderPath = fixedOnedrivePath.Substring(0, fixedOnedrivePath.LastIndexOf("/") + 1);

            fixedOnedrivePath = FixPathForCreateFile(folderPath);
            if (folderPath.Length > 2)
            {
                fixedOnedrivePath = FixPathForCreateFileOnSubFolders(folderPath);
            }

            var reference = ODConnection.ItemReferenceForSpecialFolder("approot", onedrivePath);

            reference.Path = fixedOnedrivePath;

            var modified = ItemUploadOptions.Default;
            modified.NameConflict = NameConflictBehavior.Replace;
            localFile.Position = 0;
            var res2 = await Connection.PutNewFileToParentItemAsync(reference, filename, localFile, modified);

        }

        public async void CreateFile(IOnedriveControl _this, string onedrivePath, EventHandler<CreateFileResult> callback)
        {
            string fixedOnedrivePath = onedrivePath.Replace("\\", "/");
            string folderPath = fixedOnedrivePath.Substring(0, fixedOnedrivePath.LastIndexOf("/") + 1);
            fixedOnedrivePath = FixPathForCreateFile(folderPath);

            var reference = ODConnection.ItemReferenceForSpecialFolder("approot");

            reference.Path = fixedOnedrivePath;

            if (!reference.IsValid())
            {
                throw new Exception();
            }

            // Create inmemory stream that uploads when is goes disposed.
            OnedriveStream stream = new OnedriveStream(_this, onedrivePath);

            CreateFileResult result = new CreateFileResult();
            result.Success = true;
            result.FileStream = stream;
            callback(this, result);
        }

        public async void CreateFolder(string onedrivePath, EventHandler<CreateFolderResult> callback)
        {
            onedrivePath = onedrivePath.Replace('\\', '/');
            if (onedrivePath[onedrivePath.Length - 1] == '/')
            {
                onedrivePath = onedrivePath.Substring(0, onedrivePath.Length - 1);
            }

            string fixedOnedrivePath = onedrivePath.Replace("\\", "/");
            string folderName = fixedOnedrivePath.Substring(fixedOnedrivePath.LastIndexOf("/") + 1);
            string folderPath = fixedOnedrivePath.Substring(0, fixedOnedrivePath.LastIndexOf("/") + 1);

            fixedOnedrivePath = FixPathForCreateFile(folderPath);

            var reference = ODConnection.ItemReferenceForSpecialFolder("approot");

            reference.Path = fixedOnedrivePath;

            if (!reference.IsValid())
            {
                throw new Exception();
            }

            // Create folder on one drive.
            var res2 = await Connection.CreateFolderAsync(reference, folderName);

            CreateFolderResult result = new CreateFolderResult();
            result.Success = true;
            callback(this, result);
        }
    }
}
